package com.bruce.exec.utils;

import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.text.StrPool;
import cn.hutool.core.util.RuntimeUtil;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.WinNT;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;

/**
 * @author xin.ding
 * @date 2021/4/16 15:53
 */
public class WinProcess implements ProcessHandler {

    @Override
    public String getProcessId(Process process) {
        if (process == null) {
            return null;
        }
        if (process.getClass().getName().equals("java.lang.Win32Process")
                || process.getClass().getName().equals("java.lang.ProcessImpl")) {
            try {
                Field f = process.getClass().getDeclaredField("handle");
                f.setAccessible(true);
                long handl = f.getLong(process);

                Kernel32 kernel = Kernel32.INSTANCE;
                WinNT.HANDLE handle = new WinNT.HANDLE();
                handle.setPointer(Pointer.createConstant(handl));
                int ret = kernel.GetProcessId(handle);
                return String.valueOf(ret);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    @Override
    public boolean killProcess(Process process) {
        String parentPid = winProcessId(process);
        boolean killed = false;
        if (parentPid == null || parentPid.trim().equals("")) {
            return true;
        }
        Runtime runtime = Runtime.getRuntime();
        try {
            Process pro = runtime.exec(new String[]{"taskkill", "/F", "/T", "/PID", parentPid});
            try {
                int i = pro.waitFor();
                if (i == 0) {
                    killed = true;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return killed;
    }

    @Override
    public boolean killProcess(String pid) {
        boolean killed = false;
        Runtime runtime = Runtime.getRuntime();
        try {
            Process pro = runtime.exec(new String[]{"taskkill", "/F", "/T", "/PID", pid});
            try {
                int code = pro.waitFor();
                if (code == 0) {
                    killed = true;
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return killed;
    }

    /**
     * 进程是否存活
     *
     * @param pid 进程Pid
     * @return bool
     */
    @Override
    public boolean isActivePid(String pid) {
        // UshUpgradeService.exe          180 Services                   0      1,588 K
        String docCommand = "tasklist | findstr " + pid;
        String ret = RuntimeUtil.execForStr(new String[]{"cmd", "/c", docCommand});
        if (CharSequenceUtil.isNotBlank(ret)) {
            final String[] split = ret.split(StrPool.CRLF);
            for (String s : split) {
                if (!s.contains(pid)) {
                    continue;
                }
                final String trim = s.substring(s.indexOf(" ")).trim();
                return pid.equalsIgnoreCase(trim.substring(0, trim.indexOf(" ")));
            }
        }
        return false;
    }

    @Override
    public String getOtherPid(String exeName) {
        Runtime runtime = Runtime.getRuntime();
        try {
            Process pro = runtime.exec(new String[]{"tasklist", "/FI", String.format("\"imagename eq %s\"", exeName), "/NH"});
            BufferedReader br = new BufferedReader(new InputStreamReader(pro.getInputStream(), StandardCharsets.UTF_8));
            String str = "";
            while ((str = br.readLine()) != null) {
                if (str.trim().equals("") || !str.contains(exeName)) {
                    continue;
                }
                String trim = str.substring(exeName.length()).trim();
                br.close();
                return trim.split(" ")[0].trim();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * windows 得到 窗口进程 id
     *
     * @param process process
     * @return pid
     */
    private static String winProcessId(Process process) {
        if (process.getClass().getName().equals("java.lang.Win32Process")
                || process.getClass().getName().equals("java.lang.ProcessImpl")) {
            try {
                Field f = process.getClass().getDeclaredField("handle");
                f.setAccessible(true);
                long handl = f.getLong(process);

                Kernel32 kernel = Kernel32.INSTANCE;
                WinNT.HANDLE handle = new WinNT.HANDLE();
                handle.setPointer(Pointer.createConstant(handl));
                int ret = kernel.GetProcessId(handle);
                return String.valueOf(ret);
            } catch (Throwable e) {
                e.printStackTrace();
            }
        }
        return null;
    }

}
